package org.springframework.web.servlet.ajax.json;

import java.io.IOException;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.web.servlet.ViewResolver;

/**
 * @author Charles Tassoni
 *
 */
public class PartialsCoreImpl implements PartialsCore{

	//TODO Maybe we'll find all the viewResolvers in the future, but for now
	//we expect to be configured with one.
	private ViewResolver viewResolverDelegate;

	private String jsonRequestAttribute = "jsonAttr";
	private String jsonResponseHeaderName = "EXPECT_JSON_CONTENT";
	//TODO Document this.  It's the json key that your javascript will take as a command to redirect to the
	//json value's url
	private String redirectCommand = "redirectURL";  
	private boolean throwExceptionIfRenderedContentIsEmpty = true;

	private JsonSerializer jsonSerializer = new DefaultJsonSerializer();

	public void setThrowExceptionIfRenderedContentIsEmpty(
			boolean throwExceptionIfRenderedContentIsEmpty) {
		this.throwExceptionIfRenderedContentIsEmpty = throwExceptionIfRenderedContentIsEmpty;
	}

	public JsonSerializer getJsonSerializer(){
		return jsonSerializer;
	}
	public void setJsonSerializer(JsonSerializer jsonSerializer) {
		this.jsonSerializer = jsonSerializer;
	}


	public void setJsonRequestAttribute(String jsonRequestAttribute) {
		this.jsonRequestAttribute = jsonRequestAttribute;
	}

	public void setJsonResponseHeaderName(String jsonResponseHeaderName) {
		this.jsonResponseHeaderName = jsonResponseHeaderName;
	}

	public void setRedirectCommand(String redirectCommand) {
		this.redirectCommand = redirectCommand;
	}

	public void setViewResolverDelegate(ViewResolver viewResolverDelegate) {
		this.viewResolverDelegate = viewResolverDelegate;
	}


	private  ViewResolver makeHoldsContentViewResolver(){
		HoldsContentViewResolver holdsContent = new HoldsContentViewResolver();
		holdsContent.setDelegate(this.viewResolverDelegate);
		return holdsContent;
	}

	private HoldsContentView getView(String viewName){
		try {
			return (HoldsContentView) makeHoldsContentViewResolver().resolveViewName(viewName, LocaleContextHolder.getLocale());
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	public LinkedHashMap makeMap(List<String> keys, List<String> viewNames, Map modelMap,
			HttpServletRequest request, HttpServletResponse response){
		LinkedHashMap map = new LinkedHashMap<String, String>();
		for(int i = 0, n = keys.size(); i < n; i++){
			String viewName = viewNames.get(i);
			HoldsContentView view = getView(viewName);
			try{
				view.render(modelMap, request, response);
				if(view.getContent().toString().equals("") && throwExceptionIfRenderedContentIsEmpty)
					throw new RuntimeException("No content rendered for view " + viewName +
							".  Could it be that view does not exist?");
				map.put(keys.get(i), view.getContent().toString());
			}catch(Exception ex){
				throw new RuntimeException(ex);
			}
		}

		return map;
	}


	public void writeJsonRedirect(String relativePath, HttpServletRequest request,
			HttpServletResponse response){
		Map map = new LinkedHashMap();  //There's only one element, so it could be any kind of  map!
		String destination = request.getContextPath() + "/" + relativePath;
		map.put(this.redirectCommand, destination);
		write(response, jsonSerializer.mapToJson(map));
	}

	
	public void write(HttpServletResponse response, String jsonContent) {
		//response.setHeader(jsonResponseHeaderName, "true");
		try{
			response.getWriter().write(jsonContent);
		}catch(IOException ex){
			throw new RuntimeException(ex);
		}finally{
			try{
				response.getWriter().close();
			}catch(IOException ex){
				//TODO No printlns allowed, but I suppose this is something that needs to be logged.
				System.out.println("Couldn't close response's writer");
			}
		}

	}

	@Override
	protected void finalize() throws Throwable {
		this.viewResolverDelegate = null;
		super.finalize();
	}

}
